package org.example.http;

import org.example.constant.HttpMethod;
import org.example.util.URLEncodedUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class SimpleHttpRequest extends AbstractHttpRequest {

    private static final Logger log = LoggerFactory.getLogger(SimpleHttpRequest.class);

    private static final String URL_PREFIX = "http://";
    private static final String CONTENT_TYPE = "Content-Type";
    private static final String HEADER_JSON = "application/json;charset=uft-8";
    private static final String HEADER_FORM = "application/x-www-form-urlencoded; charset=utf-8";
    /**
     * 参数 (要么String要么Map<>)
     */
    private Object params;
    /**
     * 地址
     */
    private final String url;
    /**
     * 方法
     */
    private HttpMethod method = HttpMethod.GET;
    /**
     * url encoding 编码
     */
    private Charset charset = StandardCharsets.UTF_8;

    public SimpleHttpRequest(String url) {
        this.url = transformedUrl(url);
    }

    public SimpleHttpRequest(String url, HttpMethod method, Object params, List<Header> headers) {
        this.url = transformedUrl(url);
        this.addHeader(headers);
        this.method = method;
        this.params = params;
    }

    public void setCharset(Charset charset) {
        this.charset = charset;
    }

    @Override
    @SuppressWarnings("all")
    public SimpleHttpRequest addParam(Object name, Object value) {
        if (method != HttpMethod.GET && params instanceof Map) {
            ((Map) this.params).put(name, value);
        }
        return this;
    }

    @Override
    @SuppressWarnings("all")
    public SimpleHttpRequest addParam(Map params) {
        if (method != HttpMethod.GET && params instanceof Map) {
            ((Map) this.params).putAll(params);
        }
        return this;
    }

    @Override
    public HttpResponse exec() {
        InputStream in = null;
        PrintWriter out = null;
        try {
            URL url = new URL(this.url);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod(this.method.name());
            if ("https".equals(url.getProtocol().toLowerCase())) {
                HttpsURLConnection httpsURLConnection = (HttpsURLConnection) connection;
                httpsURLConnection.setHostnameVerifier((hostname, session) -> true);
                httpsURLConnection.setSSLSocketFactory(socketFactory);
            }
            // 设置请求头
            if (!headers.isEmpty()) {
                headers.forEach(v -> connection.setRequestProperty(v.getName(), v.getValue()));
            }
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            // 获取连接
            connection.connect();
            out = new PrintWriter(connection.getOutputStream());
            if (HttpMethod.GET != this.method && params != null) {
                out.print(convertParams());
            }
            out.flush();
            in = connection.getInputStream();
            BufferedReader buffer = new BufferedReader(new InputStreamReader(in, charset));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = buffer.readLine()) != null) {
                sb.append(line);
            }
            return SimpleHttpResponse.builder()
                    .code(connection.getResponseCode())
                    .message(connection.getResponseMessage())
                    .headerFields(connection.getHeaderFields())
                    .body(sb.toString()).build();
        } catch (IOException e) {
            log.error("http请求失败", e);
            throw new RuntimeException("http请求失败");
        } finally {
            try {
                if (null != in) {
                    in.close();
                }
                if (null != out) {
                    out.close();
                }
            } catch (Exception e) {
                log.error("关闭流异常:", e);
            }
        }
    }

    public static HttpResponse doGet(String url, Header... headers) {
        return new SimpleHttpRequest(url).addHeader(Arrays.asList(headers)).exec();
    }

    public static HttpResponse doPost(String url, Map<String, Object> params, Header... headers) {
        return new SimpleHttpRequest(url, HttpMethod.POST, params, Arrays.asList(headers)).exec();
    }

    public static HttpResponse doPost(String url, String jsonParams, Header... headers) {
        List<Header> headerList = new ArrayList<>(Arrays.asList(headers));
        headerList.add(new SimpleHeader(CONTENT_TYPE, HEADER_JSON));
        return new SimpleHttpRequest(url, HttpMethod.POST, jsonParams, headerList).exec();
    }

    @SuppressWarnings("all")
    private String convertParams() {
        if (this.params instanceof String) {
            return (String) params;
        }
        if (this.params instanceof Map) {
            return URLEncodedUtils.format((Map) params, this.charset.name());
        }
        return null;
    }

    private String transformedUrl(String url) {
        if (null == url || "".equals(url.trim())) {
            throw new RuntimeException("URL地址不正确");
        }
        if (url.startsWith("http") || url.startsWith("https")) {
            return url;
        }
        return URL_PREFIX + url;
    }
}
